const chokidar = require("chokidar");
const bodyParser = require("body-parser");
const chalk = require("chalk");
const path = require("path");
const Mock = require("mockjs");

const mockDir = path.join(process.cwd(), "mock");

// 注册路由
function registerRoutes(app) {
  let mockLastIndex;
  const { mocks } = require("./index.js");
  // 遍历所有的mocks数组(mcok拦截配置) 给每个配置生成一个mock服务器，返回一个mock服务器数组
  const mocksForServer = mocks.map((route) => {
    // 给每个mcok拦截配置都执行了responseFake方法，传入配置的请求地址、请求方式、响应函数
    return responseFake(route.url, route.type, route.response);
  });
  // 遍历这个mock服务器数组，通过 app 这个应用实例来注册路由  【app其实就是webpack给我起的那个服务器】
  for (const mock of mocksForServer) {
    app[mock.type](mock.url, mock.response); // 例如： app.get('地址',处理函数)
    mockLastIndex = app._router.stack.length;
  }
  const mockRoutesLength = Object.keys(mocksForServer).length;
  return {
    mockRoutesLength: mockRoutesLength,
    mockStartIndex: mockLastIndex - mockRoutesLength,
  };
}

function unregisterRoutes() {
  Object.keys(require.cache).forEach((i) => {
    if (i.includes(mockDir)) {
      delete require.cache[require.resolve(i)];
    }
  });
}

// for mock server
// 生成一个mock服务器的路由配置
const responseFake = (url, type, respond) => {
  // 返回一个对象
  return {
    // 路由地址  【重点】  【环境变量VUE_APP_BASE_API+mock配置里面url路径】 组成完整匹配地址
    url: new RegExp(`${process.env.VUE_APP_BASE_API}${url}`),
    // url: new RegExp(`/mock${url}`),
    // 路由方式
    type: type || "get",
    // 处理函数
    response(req, res) {
      // 2个形参，第一个是前端的请求；第二个是服务器的响应
      console.log("request invoke:" + req.path);
      // respond 就是mock拦截配置里面第三个处理函数参数
      res.json(
        Mock.mock(respond instanceof Function ? respond(req, res) : respond)
      );
    },
  };
};

// 暴露出去
module.exports = (app) => {
  // 解析app里面body，也就是解析请求体
  // parse app.body
  // https://expressjs.com/en/4x/api.html#req.body
  app.use(bodyParser.json());
  app.use(
    bodyParser.urlencoded({
      extended: true,
    })
  );
  // 注册Mock路由
  const mockRoutes = registerRoutes(app); // 【核心位置】
  var mockRoutesLength = mockRoutes.mockRoutesLength;
  var mockStartIndex = mockRoutes.mockStartIndex;

  // watch files, hot reload mock server
  // 监听mock文件夹下面的变动，如果有变动就输出一些信息在命令行控制台
  chokidar
    .watch(mockDir, {
      ignored: /mock-server/,
      ignoreInitial: true,
    })
    .on("all", (event, path) => {
      if (event === "change" || event === "add") {
        try {
          // remove mock routes stack
          app._router.stack.splice(mockStartIndex, mockRoutesLength);

          // clear routes cache
          unregisterRoutes();

          const mockRoutes = registerRoutes(app);
          mockRoutesLength = mockRoutes.mockRoutesLength;
          mockStartIndex = mockRoutes.mockStartIndex;

          console.log(
            chalk.magentaBright(
              `\n > Mock Server hot reload success! changed  ${path}`
            )
          );
        } catch (error) {
          console.log(chalk.redBright(error));
        }
      }
    });
};
